package uk.ac.bath.util;

import java.util.*;

public class MyRandom {

    static long seed;

    static public long grabSeed() {
        return seed;
    }

    static synchronized public void setSeed(long s) {
        //	this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
        seed = s;
    //	haveNextNextGaussian = false;
    }

    static public long next(int bits) {
        seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
        return (int) (seed >>> (48 - bits));
    }

    static public int nextInt() {
        return (int) next(32);
    }

    /**
     * random integer between 0 and (n-1)
     *
     * @param n
     * @return
     */
    static public int nextInt(int n) {
        if (n <= 0) {
            throw new IllegalArgumentException("n must be positive");
        }

        if ((n & -n) == n) // i.e., n is a power of 2
        {
            return (int) ((n * (long) next(31)) >> 31);
        }

        int bits, val;
        do {
            bits = (int) next(31);
            val = bits % n;
        } while (bits - val + (n - 1) < 0);
        return val;
    }

    static public double nextDouble() {
        return (((long) next(26) << 27) + next(27)) / (double) (1L << 53);
    }

    static synchronized public double nextGaussian() {
        double v1, v2, s;
        do {
            v1 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
            v2 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
            s = v1 * v1 + v2 * v2;
        } while (s >= 1 || s == 0);
        double multiplier = Math.sqrt(-2 * Math.log(s) / s);
        //	 nextNextGaussian = v2 * multiplier;
        //	 haveNextNextGaussian = true;
        return v1 * multiplier;
    }

    public static void main(String args[]) {
        long seed[] = new long[10];


        for (int i = 0; i < 10; i++) {
            seed[i] = MyRandom.grabSeed();
            System.out.println(MyRandom.nextGaussian());
        }


        for (int i = 0; i < 10; i++) {
            MyRandom.setSeed(seed[i]);
            System.out.println(MyRandom.nextGaussian());
        }
    }
}
